const square = n => n * n;
export default class Vector3 {
  x: number;
  readonly y: number;
  readonly z: number;

  constructor(x: number, y: number, z: number) {
    this.x = x;
    this.y = y;
    this.z = z;
  }

  static zero: Vector3 = new Vector3(0, 0, 0);

  copy(): Vector3 {
    return new Vector3(this.x, this.y, this.z);
  }

  length(): number {
    return Math.sqrt(square(this.x) + square(this.y) + square(this.z));
  }

  sqrLength(): number {
    return square(this.x) + square(this.y) + square(this.z);
  }

  normalize(): Vector3 {
    const inv = 1 / this.length();
    return new Vector3(this.x * inv, this.y * inv, this.z * inv);
  }

  negate(): Vector3 {
    return new Vector3(-this.x, -this.y, -this.z);
  }

  add(v: Vector3): Vector3 {
    return new Vector3(this.x + v.x, this.y + v.y, this.z + v.z);
  }

  subtract(v: Vector3): Vector3 {
    return new Vector3(this.x - v.x, this.y - v.y, this.z - v.z);
  }

  multiply(f: number): Vector3 {
    return new Vector3(this.x * f, this.y * f, this.z * f);
  }

  divide(f: number): Vector3 {
    const inv_f = 1 / f;
    return new Vector3(this.x * inv_f, this.y * inv_f, this.z * inv_f);
  }

  dot(v) {
    return this.x * v.x + this.y * v.y + this.z * v.z;
  }

  cross(v) {
    return new Vector3(
      -this.z * v.y + this.y * v.z,
      this.z * v.x - this.x * v.z,
      -this.y * v.x + this.x * v.y
    );
  }

}
